/*
 * This file is part of Cadmium.
 * Copyright (C) 2007-2010 Xavier Clerc.
 *
 * Cadmium is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Cadmium is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package fr.x9c.cadmium.primitives.cadmiummath;

import java.math.BigDecimal;
import java.math.BigInteger;

import fr.x9c.cadmium.kernel.Block;
import fr.x9c.cadmium.kernel.CodeRunner;
import fr.x9c.cadmium.kernel.Custom;
import fr.x9c.cadmium.kernel.Fail;
import fr.x9c.cadmium.kernel.Primitive;
import fr.x9c.cadmium.kernel.PrimitiveProvider;
import fr.x9c.cadmium.kernel.Value;
import fr.x9c.cadmium.primitives.cadmium.Cadmium;

/**
 * This class provides the primitives for big decimal manipulation.
 *
 * @author <a href="mailto:cadmium@x9c.fr">Xavier Clerc</a>
 * @version 1.1
 * @since 1.1
 */
@PrimitiveProvider
public final class BigDecimals {

    /**
     * No instance of this class.
     */
    private BigDecimals() {
    } // end empty constructor

    /**
     * Returns a big decimal constant.
     * @param ctxt context
     * @param constant constant value to be promoted from int to big decimal, <br/>
     *                 should be one of: zero, one, ten
     * @return the passed value, as a big decimal
     * @throws Fail.Exception the passed value is not one of the following: zero, one, ten
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_get_constant(final CodeRunner ctxt,
                                                            final Value constant)
        throws Fail.Exception {
        try {
            switch (constant.asLong()) {
            case 0: return Cadmium.createObject(BigDecimal.ZERO);
            case 1: return Cadmium.createObject(BigDecimal.ONE);
            case 10: return Cadmium.createObject(BigDecimal.TEN);
            default:
                Fail.invalidArgument("CadmiumMath.BigDecimal.get_constant");
                return Value.ZERO; // never reached
            } // end switch
        } catch (final Fail.Exception fe) {
            throw fe;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_get_constant(CodeRunner, Value)'

    /**
     * Creates a new big decimal.
     * @param ctxt context
     * @param biginteger big integer
     * @return a new big decimal
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_make_of_big_integer(final CodeRunner ctxt,
                                                                   final Value biginteger)
        throws Fail.Exception {
        try {
            return Cadmium.createObject(new BigDecimal((BigInteger) biginteger.asBlock().asCustom()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_make_of_big_integer(CodeRunner, Value)'

    /**
     * Creates a new big decimal.
     * @param ctxt context
     * @param mc math context
     * @param biginteger big integer
     * @return a new big decimal
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_make_of_big_integer_ctxt(final CodeRunner ctxt,
                                                                        final Value mc,
                                                                        final Value biginteger)
        throws Fail.Exception {
        try {
            return Cadmium.createObject(new BigDecimal((BigInteger) biginteger.asBlock().asCustom(),
                                                       Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_make_of_big_integer_ctxt(CodeRunner, Value, Value)'

    /**
     * Creates a new big decimal.
     * @param ctxt context
     * @param biginteger big integer
     * @param scale scale of the result
     * @return a new big decimal
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_make_of_big_integer_scale(final CodeRunner ctxt,
                                                                         final Value biginteger,
                                                                         final Value scale)
        throws Fail.Exception {
        try {
            return Cadmium.createObject(new BigDecimal((BigInteger) biginteger.asBlock().asCustom(),
                                                       scale.asLong()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_make_of_big_integer_scale(CodeRunner, Value, Value)'

    /**
     * Creates a new big decimal.
     * @param ctxt context
     * @param mc math context
     * @param biginteger big integer
     * @param scale scale of the result
     * @return a new big decimal
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_make_of_big_integer_scale_ctxt(final CodeRunner ctxt,
                                                                              final Value mc,
                                                                              final Value biginteger,
                                                                              final Value scale)
        throws Fail.Exception {
        try {
            return Cadmium.createObject(new BigDecimal((BigInteger) biginteger.asBlock().asCustom(),
                                                       scale.asLong(),
                                                       Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_make_of_big_integer_scale_ctxt(CodeRunner, Value, Value, Value)'

    /**
     * Creates a new big decimal.
     * @param ctxt context
     * @param f float
     * @return a new big decimal
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_make_of_float(final CodeRunner ctxt,
                                                             final Value f)
        throws Fail.Exception {
        try {
            return Cadmium.createObject(new BigDecimal(f.asBlock().asDouble()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_make_of_float(CodeRunner, Value, Value)'

    /**
     * Creates a new big decimal.
     * @param ctxt context
     * @param mc math context
     * @param f float
     * @return a new big decimal
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_make_of_float_ctxt(final CodeRunner ctxt,
                                                                  final Value mc,
                                                                  final Value f)
        throws Fail.Exception {
        try {
            return Cadmium.createObject(new BigDecimal(f.asBlock().asDouble(),
                                                       Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_make_of_float_ctxt(CodeRunner, Value, Value)'

    /**
     * Creates a new big decimal.
     * @param ctxt context
     * @param i int32
     * @return a new big decimal
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_make_of_int32(final CodeRunner ctxt,
                                                             final Value i)
        throws Fail.Exception {
        try {
            return Cadmium.createObject(new BigDecimal(i.asBlock().asInt32()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_make_of_int32(CodeRunner, Value)'

    /**
     * Creates a new big decimal.
     * @param ctxt context
     * @param mc math context
     * @param i int32
     * @return a new big decimal
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_make_of_int32_ctxt(final CodeRunner ctxt,
                                                                  final Value mc,
                                                                  final Value i)
        throws Fail.Exception {
        try {
            return Cadmium.createObject(new BigDecimal(i.asBlock().asInt32(),
                                                       Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_make_of_int32_ctxt(CodeRunner, Value, Value)'

    /**
     * Creates a new big decimal.
     * @param ctxt context
     * @param i int64
     * @return a new big decimal
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_make_of_int64(final CodeRunner ctxt,
                                                             final Value i)
        throws Fail.Exception {
        try {
            return Cadmium.createObject(new BigDecimal(i.asBlock().asInt64()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_make_of_int64(CodeRunner, Value)'

    /**
     * Creates a new big decimal.
     * @param ctxt context
     * @param mc math context
     * @param i int64
     * @return a new big decimal
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_make_of_int64_ctxt(final CodeRunner ctxt,
                                                                  final Value mc,
                                                                  final Value i)
        throws Fail.Exception {
        try {
            return Cadmium.createObject(new BigDecimal(i.asBlock().asInt64(),
                                                       Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_make_of_int64_ctxt(CodeRunner, Value, Value)'

    /**
     * Creates a new big decimal.
     * @param ctxt context
     * @param s string
     * @return a new big decimal
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_make_of_string(final CodeRunner ctxt,
                                                              final Value s)
        throws Fail.Exception {
        try {
            return Cadmium.createObject(new BigDecimal(s.asBlock().asString()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_make_of_string(CodeRunner, Value)'

    /**
     * Creates a new big decimal.
     * @param ctxt context
     * @param mc math context
     * @param s string
     * @return a new big decimal
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_make_of_string_ctxt(final CodeRunner ctxt,
                                                                   final Value mc,
                                                                   final Value s)
        throws Fail.Exception {
        try {
            return Cadmium.createObject(new BigDecimal(s.asBlock().asString(),
                                                       Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_make_of_string_ctxt(CodeRunner, Value, Value)'

    /**
     * Returns the absolute value of the passed value.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the absolute value of the passed value
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_abs(final CodeRunner ctxt,
                                                   final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.abs());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_abs(CodeRunner, Value)'

    /**
     * Returns the absolute value of the passed value.
     * @param ctxt context
     * @param mc math context
     * @param bigdecimal big decimal
     * @return the absolute value of the passed value
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_abs_ctxt(final CodeRunner ctxt,
                                                        final Value mc,
                                                        final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.abs(Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_abs_ctxt(CodeRunner, Value, Value)'

    /**
     * Returns the addition of the passed values.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return the addition of the passed values
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_add(final CodeRunner ctxt,
                                                   final Value bigdecimal,
                                                   final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.add(bd2));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_add(CodeRunner, Value, Value)'

    /**
     * Returns the addition of the passed values.
     * @param ctxt context
     * @param mc math context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return the addition of the passed values
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_add_ctxt(final CodeRunner ctxt,
                                                        final Value mc,
                                                        final Value bigdecimal,
                                                        final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.add(bd2, Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_add_ctxt(CodeRunner, Value, Value, Value)'

    /**
     * Converts the passed big decimal into a byte value
     * (checking for lost information).
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as an byte
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_byte_value_exact(final CodeRunner ctxt,
                                                                final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Value.createFromLong(bd.byteValueExact());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_byte_value_exact(CodeRunner, Value)'

    /**
     * Compares the passed values.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return -1, 0, or 1 as <i>bigdecimal</i> is less than, equal to,
     *         or greater than <i>bigdecimal</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_compare_to(final CodeRunner ctxt,
                                                          final Value bigdecimal,
                                                          final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Value.createFromLong(bd.compareTo(bd2));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_compare_to(CodeRunner, Value, Value)'

    /**
     * Returns the division of the passed values.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return <i>bigdecimal / bigdecimal2</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_divide(final CodeRunner ctxt,
                                                      final Value bigdecimal,
                                                      final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.divide(bd2));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_divide(CodeRunner, Value, Value)'

    /**
     * Returns the division of the passed values.
     * @param ctxt context
     * @param scale scale of result
     * @param mode rounding mode
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return <i>bigdecimal / bigdecimal2</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_divide_scale_mode(final CodeRunner ctxt,
                                                                 final Value scale,
                                                                 final Value mode,
                                                                 final Value bigdecimal,
                                                                 final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.divide(bd2, scale.asLong(), Misc.decodeRoundingMode(mode)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_divide_scale_mode(CodeRunner, Value, Value, Value, Value)'

    /**
     * Returns the division of the passed values.
     * @param ctxt context
     * @param mc math context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return <i>bigdecimal / bigdecimal2</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_divide_ctxt(final CodeRunner ctxt,
                                                           final Value mc,
                                                           final Value bigdecimal,
                                                           final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.divide(bd2, Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_divide_ctxt(CodeRunner, Value, Value, Value)'

    /**
     * Returns the division of the passed values.
     * @param ctxt context
     * @param mode rounding mode
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return <i>bigdecimal / bigdecimal2</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_divide_mode(final CodeRunner ctxt,
                                                           final Value mode,
                                                           final Value bigdecimal,
                                                           final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.divide(bd2, Misc.decodeRoundingMode(mode)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_divide_mode(CodeRunner, Value, Value, Value)'

    /**
     * Returns the quotient and remainder of passed values.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return the quotient and remainder of passed values
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_divide_and_remainder(final CodeRunner ctxt,
                                                                    final Value bigdecimal,
                                                                    final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            final BigDecimal[] dr = bd.divideAndRemainder(bd2);
            final Block res = Block.createBlock(0,
                                                Cadmium.createObject(dr[0]),
                                                Cadmium.createObject(dr[1]));
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_divide_and_remainder(CodeRunner, Value, Value)'

    /**
     * Returns the quotient and remainder of passed values.
     * @param ctxt context
     * @param mc math context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return the quotient and remainder of passed values
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_divide_and_remainder_ctxt(final CodeRunner ctxt,
                                                                        final Value mc,
                                                                        final Value bigdecimal,
                                                                        final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            final BigDecimal[] dr = bd.divideAndRemainder(bd2, Misc.decodeMathContext(mc));
            final Block res = Block.createBlock(0,
                                                Cadmium.createObject(dr[0]),
                                                Cadmium.createObject(dr[1]));
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_divide_and_remainder_ctxt(CodeRunner, Value, Value, Value)'

    /**
     * Returns the integral division of the passed values.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return <i>bigdecimal / bigdecimal2</i> rounded down
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_divide_to_integral_value(final CodeRunner ctxt,
                                                                        final Value bigdecimal,
                                                                        final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.divideToIntegralValue(bd2));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_divide_to_integral_value(CodeRunner, Value, Value)'

    /**
     * Returns the integral division of the passed values.
     * @param ctxt context
     * @param mc math context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return <i>bigdecimal / bigdecimal2</i> rounded down
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_divide_to_integral_value_ctxt(final CodeRunner ctxt,
                                                                             final Value mc,
                                                                             final Value bigdecimal,
                                                                             final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.divideToIntegralValue(bd2, Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_divide_to_integral_value_ctxt(CodeRunner, Value, Value, Value)'

    /**
     * Tests whether the passed values are equal.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return <tt>true</tt> if the passed values are equal,
     *         <tt>false</tt> otherwise
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_equals(final CodeRunner ctxt,
                                                      final Value bigdecimal,
                                                      final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return bd.equals(bd2) ? Value.TRUE : Value.FALSE;
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_equals(CodeRunner, Value, Value)'

    /**
     * Converts the passed big decimal into a float value
     * (checking for lost information).
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as a float
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_float_value(final CodeRunner ctxt,
                                                           final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final Block res = Block.createDouble(bd.doubleValue());
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_float_value(CodeRunner, Value)'

    /**
     * Returns the hash code of the passed value.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the hash code of the passed value
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_hash_code(final CodeRunner ctxt,
                                                         final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final Block res = Block.createCustom(Custom.INT_32_SIZE,
                                                 Custom.INT_32_OPS);
            res.setInt32(bd.hashCode());
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_hash_code(CodeRunner, Value)'

    /**
     * Converts the passed big decimal into an int value.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as an int
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_int_value(final CodeRunner ctxt,
                                                         final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Value.createFromLong(bd.intValue());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_int_value(CodeRunner, Value)'

    /**
     * Converts the passed big decimal into an int value
     * (checking for lost information).
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as an int
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_int_value_exact(final CodeRunner ctxt,
                                                               final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final int res = bd.intValueExact();
            if ((res >= Value.MIN_LONG) && (res <= Value.MAX_LONG)) {
                return Value.createFromLong(res);
            } else {
                throw new ArithmeticException("Overflow");
            } // end if/else
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_int_value_exact(CodeRunner, Value)'

    /**
     * Converts the passed big decimal into an int32 value.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as an int32
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_int32_value(final CodeRunner ctxt,
                                                           final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final Block res = Block.createCustom(Custom.INT_32_SIZE,
                                                 Custom.INT_32_OPS);
            res.setInt32(bd.intValue());
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_int32_value(CodeRunner, Value)'

    /**
     * Converts the passed big decimal into an int32 value
     * (checking for lost information).
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as an int32
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_int32_value_exact(final CodeRunner ctxt,
                                                                 final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final Block res = Block.createCustom(Custom.INT_32_SIZE,
                                                 Custom.INT_32_OPS);
            res.setInt32(bd.intValueExact());
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_int32_value_exact(CodeRunner, Value)'

    /**
     * Converts the passed big decimal into an int64 value.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as an int64
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_int64_value(final CodeRunner ctxt,
                                                           final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final Block res = Block.createCustom(Custom.INT_64_SIZE,
                                                 Custom.INT_64_OPS);
            res.setInt64(bd.longValue());
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_int64_value(CodeRunner, Value)'

    /**
     * Converts the passed big decimal into an int64 value
     * (checking for lost information).
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as an int64
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_int64_value_exact(final CodeRunner ctxt,
                                                                 final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final Block res = Block.createCustom(Custom.INT_64_SIZE,
                                                 Custom.INT_64_OPS);
            res.setInt64(bd.longValueExact());
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_int64_value_exact(CodeRunner, Value)'

    /**
     * Returns the maximum of the passed values.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return the maximum of the passed values
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_max(final CodeRunner ctxt,
                                                   final Value bigdecimal,
                                                   final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.max(bd2));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_max(CodeRunner, Value, Value)'

    /**
     * Returns the minimum of the passed values.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return the minimum of the passed values
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_min(final CodeRunner ctxt,
                                                   final Value bigdecimal,
                                                   final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.min(bd2));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_min(CodeRunner, Value, Value)'

    /**
     * Returns a big decimal equivalent to the passed one with the decimal
     * point moved to the left.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param n distance to move the decimal point
     * @return <i>bigdecimal * (10 ** -n)</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_move_point_left(final CodeRunner ctxt,
                                                               final Value bigdecimal,
                                                               final Value n)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.movePointLeft(n.asLong()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_move_point_left(CodeRunner, Value, Value)'

    /**
     * Returns a big decimal equivalent to the passed one with the decimal
     * point moved to the right.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param n distance to move the decimal point
     * @return <i>bigdecimal * (10 ** n)</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_move_point_right(final CodeRunner ctxt,
                                                                final Value bigdecimal,
                                                                final Value n)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.movePointRight(n.asLong()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_move_point_right(CodeRunner, Value, Value)'

    /**
     * Returns the multiplication of the passed values.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return the multiplication of the passed values
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_multiply(final CodeRunner ctxt,
                                                        final Value bigdecimal,
                                                        final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.multiply(bd2));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_multiply(CodeRunner, Value, Value)'

    /**
     * Returns the multiplication of the passed values.
     * @param ctxt context
     * @param mc math context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return the multiplication of the passed values
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_multiply_ctxt(final CodeRunner ctxt,
                                                             final Value mc,
                                                             final Value bigdecimal,
                                                             final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.multiply(bd2, Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_multiply_ctxt(CodeRunner, Value, Value, Value)'

    /**
     * Returns the opposite of the passed value.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the opposite of the passed value
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_negate(final CodeRunner ctxt,
                                                      final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.negate());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_negate(CodeRunner, Value)'

    /**
     * Returns the opposite of the passed value.
     * @param ctxt context
     * @param mc math context
     * @param bigdecimal big decimal
     * @return the opposite of the passed value
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_negate_ctxt(final CodeRunner ctxt,
                                                           final Value mc,
                                                           final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.negate(Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_negate_ctxt(CodeRunner, Value, Value)'

    /**
     * Returns the passed value.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed value
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_plus(final CodeRunner ctxt,
                                                    final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.plus());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_plus(CodeRunner, Value)'

    /**
     * Returns the passed value.
     * @param ctxt context
     * @param mc math context
     * @param bigdecimal big decimal
     * @return the passed value
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_plus_ctxt(final CodeRunner ctxt,
                                                         final Value mc,
                                                         final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.plus(Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_plus_ctxt(CodeRunner, Value, Value)'

    /**
     * Returns the passed value raised to a given power.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param n power to raise to
     * @return <i>bigdecimal ** n</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_pow(final CodeRunner ctxt,
                                                   final Value bigdecimal,
                                                   final Value n)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.pow(n.asLong()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_pow(CodeRunner, Value, Value)'

    /**
     * Returns the passed value raised to a given power.
     * @param ctxt context
     * @param mc math context
     * @param bigdecimal big decimal
     * @param n power to raise to
     * @return <i>bigdecimal ** n</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_pow_ctxt(final CodeRunner ctxt,
                                                        final Value mc,
                                                        final Value bigdecimal,
                                                        final Value n)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.pow(n.asLong(), Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_pow_ctxt(CodeRunner, Value, Value, Value)'

    /**
     * Returns the precision of the passed value.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the precision of the passed value
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_precision(final CodeRunner ctxt,
                                                         final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Value.createFromLong(bd.precision());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_precision(CodeRunner, Value)'

    /**
     * Returns the remainder of the passed values.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return the remainder of the passed values
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_remainder(final CodeRunner ctxt,
                                                         final Value bigdecimal,
                                                         final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.remainder(bd2));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_remainder(CodeRunner, Value, Value)'

    /**
     * Returns the remainder of the passed values.
     * @param ctxt context
     * @param mc math context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return the remainder of the passed values
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_remainder_ctxt(final CodeRunner ctxt,
                                                              final Value mc,
                                                              final Value bigdecimal,
                                                              final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.remainder(bd2, Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_remainder_ctxt(CodeRunner, Value, Value, Value)'

    /**
     * Returns the rounded value of the passed value.
     * @param ctxt context
     * @param mc math context
     * @param bigdecimal big decimal
     * @return the rounded value of the passed value
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_round(final CodeRunner ctxt,
                                                     final Value mc,
                                                     final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.round(Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_round(CodeRunner, Value, Value)'

    /**
     * Returns the scale of the passed value.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the scale of the passed value
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_scale(final CodeRunner ctxt,
                                                     final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final Block res = Block.createCustom(Custom.INT_32_SIZE,
                                                 Custom.INT_32_OPS);
            res.setInt32(bd.scale());
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_scale(CodeRunner, Value)'

    /**
     * Returns a big decimal multiplied by a power of ten.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param n new scale
     * @return <i>bigdecimal * 10 ** n</i>
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_scale_by_power_of_ten(final CodeRunner ctxt,
                                                                     final Value bigdecimal,
                                                                     final Value n)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.scaleByPowerOfTen(n.asLong()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_scale_by_power_of_ten(CodeRunner, Value, Value)'

    /**
     * Returns a big decimal similar to the passed one with a given scale.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param n new scale
     * @return a big decimal similar to the passed one with a given scale
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_set_scale(final CodeRunner ctxt,
                                                         final Value bigdecimal,
                                                         final Value n)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.setScale(n.asLong()));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_set_scale(CodeRunner, Value, Value)'

    /**
     * Returns a big decimal similar to the passed one with a given scale.
     * @param ctxt context
     * @param mode rouding mode
     * @param bigdecimal big decimal
     * @param n new scale
     * @return a big decimal similar to the passed one with a given scale
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_set_scale_mode(final CodeRunner ctxt,
                                                              final Value mode,
                                                              final Value bigdecimal,
                                                              final Value n)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.setScale(n.asLong(), Misc.decodeRoundingMode(mode)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_set_scale_mode(CodeRunner, Value, Value, Value)'

    /**
     * Converts the passed big decimal into a short value
     * (checking for lost information).
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as a short
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_short_value_exact(final CodeRunner ctxt,
                                                                 final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Value.createFromLong(bd.shortValueExact());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_short_value_exact(CodeRunner, Value)'

    /**
     * Returns the signum of the passed big decimal.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return -1, 0, 1 as the value of the passed big decimal is negative,
     *         zero, or positive
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_signum(final CodeRunner ctxt,
                                                      final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Value.createFromLong(bd.signum());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_signum(CodeRunner, Value)'

    /**
     * Returns a big decimal numerically  equal to the passed one but with any
     * but with any trailing zero removed from the representation.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal with no trailing zero
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_strip_trailing_zeros(final CodeRunner ctxt,
                                                                    final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.stripTrailingZeros());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_strip_trailing_zeros(CodeRunner, Value)'

    /**
     * Returns the subtraction of the passed values.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return the subtraction of the passed values
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_subtract(final CodeRunner ctxt,
                                                        final Value bigdecimal,
                                                        final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.subtract(bd2));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_subtract(CodeRunner, Value, Value)'

    /**
     * Returns the subtraction of the passed values.
     * @param ctxt context
     * @param mc math context
     * @param bigdecimal big decimal
     * @param bigdecimal2 big decimal
     * @return the subtraction of the passed values
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_subtract_ctxt(final CodeRunner ctxt,
                                                             final Value mc,
                                                             final Value bigdecimal,
                                                             final Value bigdecimal2)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final BigDecimal bd2 = (BigDecimal) bigdecimal2.asBlock().asCustom();
            return Cadmium.createObject(bd.subtract(bd2, Misc.decodeMathContext(mc)));
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_subtract_ctxt(CodeRunner, Value, Value, Value)'

    /**
     * Converts the passed big decimal into a big integer.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as a big integer
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_to_big_integer(final CodeRunner ctxt,
                                                              final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.toBigInteger());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_to_big_integer(CodeRunner, Value)'

    /**
     * Converts the passed big decimal into a big integer
     * (checking for lost information).
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as a big integer
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_to_big_integer_exact(final CodeRunner ctxt,
                                                                    final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.toBigIntegerExact());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_to_big_integer_exact(CodeRunner, Value)'

    /**
     * Converts the passed big decimal into a string (using engineering notation).
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as a string (using engineering notation)
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_to_engineering_string(final CodeRunner ctxt,
                                                                     final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final Block res = Block.createString(bd.toEngineeringString());
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_to_engineering_string(CodeRunner, Value)'

    /**
     * Converts the passed big decimal into a string (without exponent field).
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as a string (without exponent field)
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_to_plain_string(final CodeRunner ctxt,
                                                               final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final Block res = Block.createString(bd.toPlainString());
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_to_plain_string(CodeRunner, Value)'

    /**
     * Converts the passed big decimal into a string.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the passed big decimal as a string
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_to_string(final CodeRunner ctxt,
                                                         final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            final Block res = Block.createString(bd.toString());
            return Value.createFromBlock(res);
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_to_string(CodeRunner, Value)'

    /**
     * Returns the size of an ulp for the passed big decimal.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the size of an ulp for the passed big decimal
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_ulp(final CodeRunner ctxt,
                                                   final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.ulp());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_ulp(CodeRunner, Value)'

    /**
     * Returns the unscaled value of the passed big decimal, as a big integer.
     * @param ctxt context
     * @param bigdecimal big decimal
     * @return the unscaled value of the passed big decimal, as a big integer
     * @throws Fail.Exception if any error occurs
     */
    @Primitive
    public static Value cadmiummath_bigdecimal_unscaled_value(final CodeRunner ctxt,
                                                              final Value bigdecimal)
        throws Fail.Exception {
        try {
            final BigDecimal bd = (BigDecimal) bigdecimal.asBlock().asCustom();
            return Cadmium.createObject(bd.unscaledValue());
        } catch (final Exception e) {
            Cadmium.fail(ctxt, e);
            return Value.UNIT; // never reached
        } // end try/catch
    } // end method 'cadmiummath_bigdecimal_unscaled_value(CodeRunner, Value)'

} // end class 'BigDecimals'
